package com.geovis.emergency.spd.biz.pc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.geovis.common.auth.util.AuthUtil;
import com.geovis.common.mybatis.page.PageParam;
import com.geovis.common.mybatis.page.PageResult;
import com.geovis.common.socketio.dto.SocketIoMessage;
import com.geovis.common.socketio.service.ISocketIoService;
import com.geovis.emergency.spd.biz.pc.mapper.PcDrillMapper;
import com.geovis.emergency.spd.biz.pc.mapper.PcMessageMapper;
import com.geovis.emergency.spd.biz.pc.service.IPcMessageReaderLogService;
import com.geovis.emergency.spd.biz.pc.service.IPcMessageService;
import com.geovis.emergency.spd.biz.system.service.ISystemUserService;
import com.geovis.emergency.spd.cache.UserCache;
import com.geovis.emergency.spd.entity.mobile.pojo.vo.MessageMobileVO;
import com.geovis.emergency.spd.entity.pc.entity.PcDrill;
import com.geovis.emergency.spd.entity.pc.entity.PcMessage;
import com.geovis.emergency.spd.entity.pc.entity.PcMessageReaderLog;
import com.geovis.emergency.spd.entity.pc.pojo.enums.StatusEnum;
import com.geovis.emergency.spd.entity.pc.pojo.vo.PcMessageVO;
import com.geovis.emergency.spd.entity.system.entity.SystemUser;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static io.lettuce.core.pubsub.PubSubOutput.Type.message;

/**
 * <p>
 * 应急预案指挥模块-消息通知 服务实现类
 * </p>
 *
 * @author 曾德实
 * @since 2022-04-30
 */

@Service
@RequiredArgsConstructor
@Slf4j
public class PcMessageServiceImpl extends ServiceImpl<PcMessageMapper, PcMessage> implements IPcMessageService {

    private final ISocketIoService socketIoService;

    private final ISystemUserService systemUserService;

    private final IPcMessageReaderLogService pcMessageReaderLogService;

    private final PcDrillMapper pcDrillMapper;

    @Override
    public void onKeyRead(String messageId) {
        String currentUserId = AuthUtil.getCurrentUserId();
        LambdaQueryWrapper<PcMessage> wrapper = Wrappers.<PcMessage>lambdaQuery()
                .select(PcMessage::getId)
                .notExists(StrUtil.format("select 1 from pc_message_reader_log mrl where mrl.message_id = pc_message.id and mrl.is_deleted = '0' and mrl.reader_id = '{}'", currentUserId))
                .and(s -> s.eq(PcMessage::getAcceptId, currentUserId).or().isNull(PcMessage::getAcceptId))
                .eq(StrUtil.isNotBlank(messageId), PcMessage::getId, messageId)
                .orderByDesc(PcMessage::getCreateTime);
        List<PcMessage> pcMessages = baseMapper.selectList(wrapper);
        List<PcMessageReaderLog> pcMessageReaderLogList = Lists.newArrayList();
        for (PcMessage pcMessage : pcMessages) {
            PcMessageReaderLog pcMessageReaderLog = new PcMessageReaderLog();
            pcMessageReaderLog.setMessageId(pcMessage.getId());
            pcMessageReaderLog.setReaderId(currentUserId);
            pcMessageReaderLogList.add(pcMessageReaderLog);
        }
        if (CollUtil.isNotEmpty(pcMessageReaderLogList)) {
            pcMessageReaderLogService.saveBatch(pcMessageReaderLogList);
        }
    }

    /**
     * 获取最后一条未读消息
     *
     * @param type
     * @param pcDrillId
     */
    @Override
    public PcMessageVO getLatestUnreadMessage(String type, String pcDrillId) {
        String currentUserId = AuthUtil.getCurrentUserId();
        LambdaQueryWrapper<PcMessage> wrapper = Wrappers.<PcMessage>lambdaQuery()
                .eq(PcMessage::getType, type)
                .eq(StrUtil.isNotBlank(pcDrillId), PcMessage::getPcDrillId, pcDrillId)
                .and(s -> s.eq(PcMessage::getAcceptId, currentUserId).or().isNull(PcMessage::getAcceptId))
                .orderByDesc(PcMessage::getCreateTime)
                .last("limit 1");
        PcMessage message = baseMapper.selectOne(wrapper);
        if(message==null)
        {
            return null;
        }
        //判读消息是否已读
        List<PcMessageReaderLog> logs=pcMessageReaderLogService.list(Wrappers.<PcMessageReaderLog>lambdaQuery()
                .eq(PcMessageReaderLog::getMessageId, message.getId())
                .eq(PcMessageReaderLog::getReaderId, currentUserId));
        if(!CollectionUtils.isEmpty(logs))
        {
            return null;
        }
        setDetail(message);
        PcMessageVO pcMessageVO = BeanUtil.toBean(message, PcMessageVO.class);
        if (ObjectUtil.isNotNull(pcMessageVO.getPcDrillId())) {
            PcDrill pcDrill = pcDrillMapper.selectById(pcMessageVO.getPcDrillId());
            if (ObjectUtil.isNotNull(pcDrill)) {
                pcMessageVO.setDrillName(pcDrill.getName());
            }
        }

        return pcMessageVO;
    }

    @Override
    public Long unReadCount() {
        String currentUserId = AuthUtil.getCurrentUserId();
        LambdaQueryWrapper<PcMessage> wrapper = Wrappers.<PcMessage>lambdaQuery()
                .notExists(StrUtil.format("select 1 from pc_message_reader_log mrl where mrl.message_id = pc_message.id and mrl.is_deleted = '0' and mrl.reader_id = '{}'", currentUserId))
                .and(s -> s.eq(PcMessage::getAcceptId, currentUserId).or().isNull(PcMessage::getAcceptId));
        return baseMapper.selectCount(wrapper);
    }

    @Override
    public PageResult listPage(PageParam<PcMessage> pageParam) {
        PcMessage queryDTO = pageParam.getQuery();
        IPage<PcMessageVO> page = baseMapper.selectByPage(pageParam.buildPage(), AuthUtil.getCurrentUserId(), getWrapper(queryDTO));
        setDetailList(page.getRecords());
        return new PageResult<>(page);
    }


    public LambdaQueryWrapper<PcMessage> getWrapper(PcMessage queryDTO) {
        String currentUserId = AuthUtil.getCurrentUserId();
        LambdaQueryWrapper<PcMessage> wrapper = Wrappers.<PcMessage>lambdaQuery()
                .and(s -> s.eq(PcMessage::getAcceptId, currentUserId).or().isNull(PcMessage::getAcceptId))
                .orderByDesc(PcMessage::getCreateTime);
        wrapper.eq(ObjectUtil.isNotEmpty(queryDTO.getPcDrillId()), PcMessage::getPcDrillId, queryDTO.getPcDrillId());
        return wrapper;
    }

    public void setDetailList(List<PcMessageVO> list) {
        list.forEach(this::setDetail);
    }

    public void setDetail(PcMessage pcMessage) {
        if (StatusEnum.FALSE.getEnCode().equals(pcMessage.getStatus())) {
            pcMessage.setStatus(StatusEnum.FALSE.getCode());
        } else if (StatusEnum.TRUE.getEnCode().equals(pcMessage.getStatus())) {
            pcMessage.setStatus(StatusEnum.TRUE.getCode());
        }
        if (StrUtil.isNotBlank(pcMessage.getCreateBy())) {
            SystemUser systemUser = UserCache.getUserByUserName(pcMessage.getCreateBy());
            if (systemUser != null) {
                pcMessage.setCreateBy(systemUser.getRealName());
            }
        }
    }

    @Override
    public void sendSocketMessage(PcMessage pcMessage) {
        this.sendSocketMessage(pcMessage.getType());
    }

    @Override
    public void sendSocketMessage(PcMessage pcMessage, Set<String> userList) {
        SocketIoMessage<Object> socketIoMessage = SocketIoMessage
                .builder()
                .eventName(pcMessage.getType())
                .data(pcMessage.getRelatedId())
                .toUserIdSet(userList)
                .build();
        socketIoService.sendMessage(socketIoMessage);
    }

    @Override
    public void sendSocketMessage(String eventName) {
        log.info("进入消息推送");
        List<SystemUser> systemUserList = systemUserService.list();
        if (CollUtil.isEmpty(systemUserList)) {
            log.error("人员为空");
            return;
        }
        SocketIoMessage<Object> socketIoMessage = SocketIoMessage
                .builder()
                .eventName(eventName)
                .data(eventName)
                .toUserIdSet(systemUserList.stream().map(SystemUser::getId).collect(Collectors.toSet()))
                .build();
        socketIoService.sendMessage(socketIoMessage);
        log.info("消息推送成功");
    }

    @Override
    public void sendSocketMessage(String eventName, Object data, Set<String> userList) {
        if (CollUtil.isEmpty(userList)) {
            log.error("人员为空");
            return;
        }
        SocketIoMessage<Object> socketIoMessage = SocketIoMessage
                .builder()
                .eventName(eventName)
                .data(JSONUtil.toJsonStr(data))
                .toUserIdSet(userList)
                .build();
        socketIoService.sendMessage(socketIoMessage);
    }

    @Override
    public void sendSocketMessage(String eventName, Object data) {
        log.info("进入消息推送");
        List<SystemUser> systemUserList = systemUserService.list();
        if (CollUtil.isEmpty(systemUserList)) {
            log.error("人员为空");
            return;
        }
        SocketIoMessage<Object> socketIoMessage = SocketIoMessage
                .builder()
                .eventName(eventName)
                .data(JSONUtil.toJsonStr(data))
                .toUserIdSet(systemUserList.stream().map(SystemUser::getId).collect(Collectors.toSet()))
                .build();
        socketIoService.sendMessage(socketIoMessage);
    }

    @Override
    public void sendMobileMessage(PcMessage pcMessage) {
        save(pcMessage);
        MessageMobileVO vo = new MessageMobileVO();
        vo.setMessageId(pcMessage.getId());
        vo.setTitle(pcMessage.getTitle());
        vo.setContent(pcMessage.getContent());
        vo.setStatus(pcMessage.getStatus());
        Date now = new Date();
        vo.setSendTimeDynamic(DateUtil.format(now, "HH:mm"));
        vo.setSendTime(DateUtil.format(now, "HH:mm"));
        vo.setSendTimeTag("");
        vo.setType(pcMessage.getType());
        String data = JSONUtil.toJsonStr(vo);
        SocketIoMessage<Object> socketIoMessage = SocketIoMessage
                .builder()
                .eventName(pcMessage.getType())
                .data(data)
                .toUserIdSet(CollectionUtil.set(false, pcMessage.getAcceptId()))
                .build();
        socketIoService.sendMessage(socketIoMessage);
    }

}
